﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace FirstFloor.Documents.Pdf.Fonts
{
    /// <summary>
    /// A font that defines glyph shapes using Type 1 font technology
    /// </summary>
    internal class Type1Font
        : FontBase
    {
        private int firstChar = -1;
        private int lastChar = -1;
        private double[] widths;
        private double missingWidth = -1;

        

        /// <summary>
        /// Initializes a new instance of the <see cref="Type1Font"/> class.
        /// </summary>
        /// <param name="fontDictionary">The font dictionary.</param>
        public Type1Font(DictionaryObject fontDictionary)
            : base(fontDictionary)
        {
            this.FontName = fontDictionary.Get<string>("BaseFont");
            if (this.FontName.IndexOf('+') == 6) {
                this.FontName = this.FontName.Substring(7);
                this.IsSubset = true;
            }

            //var toUnicode = fontDictionary.Get<DictionaryObject>("ToUnicode");
            //if (toUnicode != null) {
            //    using(var stream = fontDictionary.Owner.ParseStreamObject(toUnicode)){
            //        using (var reader = new StreamReader(stream.OpenFilteredStream())) {
            //            var cmap = reader.ReadToEnd();
            //        }
            //    }
            //}
        }

        /// <summary>
        /// Gets the first char.
        /// </summary>
        /// <value>The first char.</value>
        public int FirstChar
        {
            get
            {
                if (this.firstChar == -1) {
                    this.firstChar = this.FontDictionary.Get<int>("FirstChar");
                }
                return this.firstChar;
            }
        }

        /// <summary>
        /// Gets the last char.
        /// </summary>
        /// <value>The last char.</value>
        public int LastChar
        {
            get
            {
                if (this.lastChar == -1) {
                    this.lastChar = this.FontDictionary.Get<int>("LastChar");
                }
                return this.lastChar;
            }
        }

        /// <summary>
        /// Gets the widths.
        /// </summary>
        /// <value>The widths.</value>
        public double[] Widths
        {
            get
            {
                if (this.widths == null) {
                    this.widths = this.FontDictionary.Get<ArrayObject>("Widths").ToArray<double>();
                }
                return this.widths;
            }
        }

        /// <summary>
        /// The width to use for character codes whose widths are not specified in a font dictionary’s Widths array.
        /// </summary>
        /// <value>The width of the missing.</value>
        public double MissingWidth
        {
            get
            {
                if (this.missingWidth == -1) {
                    this.missingWidth = this.FontDescriptor.Get<double>("MissingWidth", 0);
                }
                return this.missingWidth;
            }
        }

        /// <summary>
        /// Parses the Glyph indices from specified string value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected override IEnumerable<GlyphIndexPoint> ParseIndices(string value)
        {
            for (int i = 0; i < value.Length; i++) {
                var c = value[i];
                var w = this.missingWidth;

                int index = c - this.FirstChar;
                if (index >= 0 && index < this.Widths.Length) {
                    w = this.Widths[index];
                }
                var glyphName = this.Encoding.GetGlyphName(c);

                if (glyphName != null) {

                    char unicodeCodePoint;
                    if (!GlyphList.TryGetCodePoint(glyphName, out unicodeCodePoint)) {
                        unicodeCodePoint = ' ';     // for now
                    }

                    yield return new GlyphIndexPoint() {
                        //GlyphIndex = GetGlyphIndex(glyphName),
                        UnicodeCodePoint = unicodeCodePoint,
                        Width = w,
                        IsSpaceCharacter = c == 32
                    };
                }
            }
        }

        /// <summary>
        /// Parses the Glyph indices from specified string value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected override IEnumerable<GlyphIndexPoint> ParseIndices(byte[] value)
        {
            return base.ParseIndices(value);
        }

        /// <summary>
        /// Gets the glyph index for specified glyph name.
        /// </summary>
        /// <param name="glyphName">Name of the glyph.</param>
        /// <returns></returns>
        protected virtual ushort? GetGlyphIndex(string glyphName)
        {
            return null;
        }
    }
}
